package org.ust.analyse;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class ClassInspector extends ASTVisitor
{
	private ArrayList < String >			statementSequence;
	private Hashtable < String , String >	variableDeclarationDictionary;

	public ClassInspector ( )
	{
		statementSequence = new ArrayList < String > ( );
		variableDeclarationDictionary = new Hashtable < String , String > ( );
	}

	@ SuppressWarnings ( "unchecked" )
	@ Override
	public boolean visit ( MethodInvocation node )
	{
		MethodInvocationStructure structure = new MethodInvocationStructure ( );
		String output = "";
		if ( node.getExpression ( ) != null )
		{
			output = node.getExpression ( ).toString ( ) + " ";
			structure.setStaticMethodExpression ( node.getExpression ( )
					.toString ( ) );
		}

		ArrayList < String > tmpArray;
		if ( node.typeArguments ( ) != null
				&& node.typeArguments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.typeArguments ( )
					.size ( ) );
			Iterator it = node.typeArguments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				output += type + " ";
				tmpArray.add ( type );
			}
			structure.setTypeArguments ( tmpArray );
		}

		output += node.getName ( ) + " ";
		structure.setMethodName ( node.getName ( ).toString ( ) );

		if ( node.arguments ( ) != null && node.arguments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.arguments ( ).size ( ) );
			Iterator it = node.arguments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				output += type + " ";
				tmpArray.add ( type );
			}
			structure.setArguments ( tmpArray );
		}

		statementSequence.add ( output );
		// System.out.println ( structure.toString ( ) );
		return super.visit ( node );
	}

	@ SuppressWarnings ( "unchecked" )
	public boolean visit ( VariableDeclarationStatement node )
	{
		VariableDeclarationStructure structure = new VariableDeclarationStructure ( );
		String key = null , value = null;

		ArrayList < String > tmpArray;

		if ( node.modifiers ( ) != null && node.modifiers ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.modifiers ( ).size ( ) );
			Iterator it = node.modifiers ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				tmpArray.add ( type );
			}
			structure.setModifiers ( tmpArray );
		}

		structure.setType ( node.getType ( ).toString ( ) );
		value = node.getType ( ).toString ( );

		if ( node.fragments ( ) != null && node.fragments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.fragments ( ).size ( ) );
			Iterator it = node.fragments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );

				StringTokenizer stringTokenizer = new StringTokenizer ( type ,
						"=" );
				if ( stringTokenizer.hasMoreElements ( ) )
				{
					key = ( String ) stringTokenizer.nextElement ( );
				}

				tmpArray.add ( type );
			}
			structure.setFragments ( tmpArray );
		}

		statementSequence.add ( structure.toString ( ) );
		variableDeclarationDictionary.put ( key , value );
		return super.visit ( node );
	}

	@ SuppressWarnings ( "unchecked" )
	public boolean visit ( FieldDeclaration node )
	{
		String value = null , key = null;
		ArrayList tmpArray = null;
		FieldDeclarationStructure structure = new FieldDeclarationStructure ( );

		structure.setType ( node.getType ( ).toString ( ) );
		value = node.getType ( ).toString ( );

		if ( node.fragments ( ) != null && node.fragments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.fragments ( ).size ( ) );
			Iterator it = node.fragments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );

				StringTokenizer stringTokenizer = new StringTokenizer ( type ,
						"=" );
				if ( stringTokenizer.hasMoreElements ( ) )
				{
					key = ( String ) stringTokenizer.nextElement ( );
				}

				tmpArray.add ( type );
			}
			structure.setFragments ( tmpArray );
		}
		variableDeclarationDictionary.put ( key , value );
		return super.visit ( node );
	}

	@ SuppressWarnings ( "unchecked" )
	public boolean visit ( ClassInstanceCreation node )
	{
		if ( ! node.getParent ( ).getClass ( ).equals (
				ExpressionStatement.class ) )
		{
			return super.visit ( node );
		}

		JITInstantiationStructure structure = new JITInstantiationStructure ( );

		if ( node.getExpression ( ) != null )
		{
			structure.setClassExpression ( node.getExpression ( ).toString ( ) );
		}

		structure.setType ( node.getType ( ).toString ( ) );

		ArrayList < String > tmpArray;
		if ( node.typeArguments ( ) != null
				&& node.typeArguments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.typeArguments ( )
					.size ( ) );
			Iterator it = node.typeArguments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				tmpArray.add ( type );
			}
			structure.setTypeArguments ( tmpArray );
		}

		if ( node.arguments ( ) != null && node.arguments ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.arguments ( ).size ( ) );
			Iterator it = node.arguments ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				tmpArray.add ( type );
			}
			structure.setArguments ( tmpArray );
		}

		statementSequence.add ( structure.toString ( ) );
		// System.out.println ( structure.toString ( ) );
		return super.visit ( node );
	}

	@ SuppressWarnings ( "unchecked" )
	@ Override
	public boolean visit ( MethodDeclaration node )
	{
		MethodDeclarationStructure structure = new MethodDeclarationStructure ( );
		ArrayList < String > tmpArray = new ArrayList < String > ( node
				.modifiers ( ).size ( ) );
		Iterator it = node.modifiers ( ).iterator ( );
		while ( it.hasNext ( ) )
		{
			String type = it.next ( ).toString ( );
			tmpArray.add ( type );
		}
		structure.setModifiers ( tmpArray );

		if ( node.typeParameters ( ) != null
				&& node.typeParameters ( ).size ( ) > 0 )
		{
			tmpArray = new ArrayList < String > ( node.typeParameters ( )
					.size ( ) );
			it = node.typeParameters ( ).iterator ( );
			while ( it.hasNext ( ) )
			{
				String type = it.next ( ).toString ( );
				tmpArray.add ( "<" + type + ">" );
			}
			structure.setTypeParameters ( tmpArray );
		}

		if ( node.getReturnType2 ( ) != null )
		{
			structure.setReturnType ( node.getReturnType2 ( ) );
		}
		else
		{
			structure.setConstructor ( true );
		}

		structure.setMethodName ( node.getName ( ).toString ( ) );

		tmpArray = new ArrayList < String > ( node.parameters ( ).size ( ) );
		it = node.parameters ( ).iterator ( );
		while ( it.hasNext ( ) )
		{
			String type = it.next ( ).toString ( );
			tmpArray.add ( type );
		}
		structure.setParameters ( tmpArray );

		tmpArray = new ArrayList < String > ( node.thrownExceptions ( ).size ( ) );
		it = node.thrownExceptions ( ).iterator ( );
		while ( it.hasNext ( ) )
		{
			String type = it.next ( ).toString ( );
			tmpArray.add ( type );
		}
		structure.setExceptions ( tmpArray );

		// System.out.println ( structure.toString ( ) );
		statementSequence.add ( structure.toString ( ) );
		return super.visit ( node );
	}

	public void process ( CompilationUnit compilationUnit )
	{
		compilationUnit.accept ( this );
	}

	public ArrayList < String > getStatementSequence ( )
	{
		return statementSequence;
	}

	public String checkLocalVariableType ( String variableName )
	{
		return this.variableDeclarationDictionary.get ( variableName );
	}
}
